﻿using CanVasLib.Diagram;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace SmartMotion.Core
{
    public class Flow
    {
       #region 构造

        public Flow()
        {
            ActionItems = new List<ActionItem>();
            Connections = new List<Connection>();
        }

        #endregion 构造
 
        #region 流程图显示属性

        public Point ViewOriginPoint { get; set; }

        public int LineHoveredColorARGB
        {
            get
            {
                return LineHoveredColor.ToArgb();
            }
            set
            {
                LineHoveredColor = Color.FromArgb(value);
            }
        }

        [JsonIgnore]
        public Color LineHoveredColor { get; set; } = Color.Blue;

        public int LineSelectedColorARGB
        {
            get
            {
                return LineSelectedColor.ToArgb();
            }
            set
            {
                LineSelectedColor = Color.FromArgb(value);
            }
        }

        [JsonIgnore()]
        public Color LineSelectedColor { get; set; } = Color.Green;

        public int LineColorARGB
        {
            get
            {
                return LineColor.ToArgb();
            }
            set
            {
                LineColor = Color.FromArgb(value);
            }
        }

        [JsonIgnore()]
        public Color LineColor { get; set; } = Color.Silver;

        public int BackColorARGB
        {
            get
            {
                return BackColor.ToArgb();
            }
            set
            {
                BackColor = Color.FromArgb(value);
            }
        }

        [JsonIgnore()]
        public Color BackColor { get; set; } = SystemColors.Control;

        public bool ShowGrid { get; set; } = false;

        #endregion 流程图显示属性

        #region 数据结构

        /// <summary>
        /// 任务集合，节点集合，动作集合，工具集合
        /// </summary>
        [Browsable(false)]
        public List<ActionItem> ActionItems { get; set; }

        /// <summary>
        /// 边的集合，连接的集合
        /// </summary>
        [Browsable(false)]
        public List<Connection> Connections { get; set; }

        /// <summary>
        /// 入边集合
        /// </summary>
        [JsonIgnore]
        private Dictionary<string, List<ActionItem>> IncomingEdges { get; set; }

        /// <summary>
        /// 出边集合
        /// </summary>
        [JsonIgnore]
        private Dictionary<string, List<ActionItem>> OutgoingEdges { get; set; }

        #endregion 数据结构

        #region 其他属性

        [Description("分组")]
        public string Group { get; set; }

        [Description("是否启用")]
        public bool InUse { get; set; }

        [Description("流程名称")]
        public string Name { get; set; }

        [Description("启动流程的事件名称")]
        public string EventName { get; set; }

        #endregion 其他属性

        #region 方法

        public void AddNode(ActionItem item)
        {
        }

        public void DelNode(ActionItem item)
        {
        }

        //private void AddEdges(TKey key, IList<TKey> outgoing)
        //{
        //    OutgoingEdges.Add(key, new HashSet<TKey>(outgoing));
        //    foreach (var dest in outgoing)
        //    {
        //        if (!IncomingEdges.TryGetValue(dest, out HashSet<TKey> incoming))
        //            IncomingEdges[dest] = new HashSet<TKey> { key };
        //        else
        //            incoming.Add(key);
        //    }
        //}

        public void GenDic()
        {
            IncomingEdges = new Dictionary<string, List<ActionItem>>();
            OutgoingEdges = new Dictionary<string, List<ActionItem>>();
            foreach (var actionItem in ActionItems)
            {
                IncomingEdges.Add(actionItem.ObjectId, new List<ActionItem>());
                OutgoingEdges.Add(actionItem.ObjectId, new List<ActionItem>());
            }

            foreach (var connection in Connections)
            {
                if (IncomingEdges.ContainsKey(connection.ToID))
                {
                    IncomingEdges[connection.ToID].Add(GetActionItem(connection.FromID));
                }
                if (OutgoingEdges.ContainsKey(connection.FromID))
                {
                    OutgoingEdges[connection.ToID].Add(GetActionItem(connection.ToID));
                }
            }
        }

        public ActionItem GetActionItem(string actionID)
        {
            return ActionItems.FirstOrDefault(tool => tool.ObjectId == actionID);
        }

        public bool Run()
        {
            bool result = true;
            GenDic();
            foreach (var actionItem in ActionItems)
            {
                actionItem.State = ActionItem.ActionState.Idle;
            }

            //有入边，入边已已执行过的执行
            while (true)
            {
                List<ActionItem> waitToRun = new List<ActionItem>();//用于存放等待执行的任务
                foreach (var actionItem in ActionItems)
                {
                    if (actionItem.State != ActionItem.ActionState.Idle) continue;
                    //执行条件1，没有入边的直接执行
                    if (IncomingEdges[actionItem.ObjectId].Count == 0)
                    {
                        actionItem.State = ActionItem.ActionState.Ready;
                        waitToRun.Add(actionItem);
                    }
                    else
                    {
                        //有入边
                        List<ActionItem> incomingActionItems = IncomingEdges[actionItem.ObjectId];
                        bool needToRun = false;
                        foreach (var incomingActionItem in incomingActionItems)
                        {
                            if (actionItem.WaitAny)//执行条件2，只要有任意一个入边执行过，就执行
                            {
                                if (incomingActionItem.State == ActionItem.ActionState.Completed)
                                {
                                    needToRun = true;
                                    break;
                                }
                            }
                            else //执行条件3，所有入边都执行过就执行
                            {
                                if (incomingActionItem.State != ActionItem.ActionState.Completed) //入边有一个没运行过或正在运行不能执行
                                {
                                    needToRun = false;
                                    break;
                                }
                                else
                                {
                                    needToRun = true;
                                }
                            }
                        }

                        if (needToRun)
                        {
                            waitToRun.Add(actionItem);
                        }
                    }
                }

                if (waitToRun.Count == 0) //如果没有等待执行的任务
                {
                    bool someTaskIsRunning = false;//以前执行的任务是否正在执行
                    
                    foreach (var actionItem in ActionItems.Where(actionItem => actionItem.State == ActionItem.ActionState.Running))
                    {
                        someTaskIsRunning = true;
                    }

                    if (!someTaskIsRunning)
                    {
                        //结束条件1,如果没有等待执行的任务,也没有任务正在执行，结束流程
                        return result;
                    }
                }
                if (waitToRun.OfType<EndNode>().Any())
                {
                    foreach (var actionItem in waitToRun)
                    {
                        if (actionItem is EndNode)
                        {
                            actionItem.State = ActionItem.ActionState.Running;
                            Task.Factory.StartNew(actionItem.Run);
                            //结束条件2,如果等待还行的集合有EndNode,直接结束流程
                            return result;
                        }
                    }
                }
                else
                {

                    //并行执行任务
                    foreach (var actionItem in waitToRun)
                    {
                        actionItem.State = ActionItem.ActionState.Running;
                        Task.Factory.StartNew(actionItem.Run);
                    }
                }
                Thread.Sleep(2);
            }
        }

        #endregion 方法
    }
}